/**
 * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "ecma_pipeline.h"
#include "optimizations/ecma_inlining.h"
#include "optimizer/ir/graph.h"

#include "optimizer/analysis/alias_analysis.h"
#include "optimizer/analysis/linear_order.h"
#include "optimizer/analysis/monitor_analysis.h"
#include "optimizer/analysis/rpo.h"
#include "optimizer/optimizations/balance_expressions.h"
#include "optimizer/optimizations/branch_elimination.h"
#include "optimizer/optimizations/checks_elimination.h"
#include "optimizer/optimizations/code_sink.h"
#include "optimizer/optimizations/deoptimize_elimination.h"
#include "optimizer/optimizations/savestate_optimization.h"
#include "optimizer/optimizations/cleanup.h"
#include "optimizer/optimizations/if_conversion.h"
#include "optimizer/optimizations/licm.h"
#include "optimizer/optimizations/licm_conditions.h"
#include "optimizer/optimizations/loop_peeling.h"
#include "optimizer/optimizations/loop_unroll.h"
#include "optimizer/optimizations/lowering.h"
#include "optimizer/optimizations/lse.h"
#include "optimizer/optimizations/memory_barriers.h"
#include "optimizer/optimizations/memory_coalescing.h"
#include "optimizer/optimizations/peepholes.h"
#include "optimizer/optimizations/phi_type_resolving.h"
#include "optimizer/optimizations/redundant_loop_elimination.h"
#include "optimizer/optimizations/regalloc/reg_alloc.h"
#include "optimizer/optimizations/scheduler.h"
#include "optimizer/optimizations/try_catch_resolving.h"
#include "optimizer/optimizations/inline_intrinsics.h"
#include "optimizer/optimizations/vn.h"
#include "optimizer/optimizations/cse.h"
#include "optimizer/optimizations/move_constants.h"
#include "optimizer/optimizations/adjust_arefs.h"
#include "plugins/ecmascript/compiler/optimizer/optimizations/inline_call_intrinsics.h"

namespace ark::compiler::ecmascript {

bool EcmaPipeline::RunOptimizations()
{
    auto graph = GetGraph();
    graph->RunPass<InlineCallIntrinsics>();
    // NOTE(schernykh): Find way to inline in AOT and OSR mode
    if (!graph->IsAotMode() && !graph->IsOsrMode()) {
        graph->RunPass<EcmaInlining>();
    }
    graph->RunPass<TryCatchResolving>();
    if (!graph->RunPass<MonitorAnalysis>()) {
        LOG(WARNING, COMPILER) << "Compiler detected incorrect monitor policy";
        return false;
    }
    graph->RunPass<Peepholes>();
    graph->RunPass<BranchElimination>();
    graph->RunPass<ValNum>();
    graph->RunPass<Cleanup>(false);
    if (graph->IsAotMode()) {
        graph->RunPass<Cse>();
    }
    graph->RunPass<InlineIntrinsics>();
    graph->RunPass<PhiTypeResolving>();
    graph->RunPass<Peepholes>();
    graph->RunPass<BranchElimination>();
    graph->RunPass<ValNum>();
    graph->RunPass<Cleanup>(false);
    graph->RunPass<ChecksElimination>();
    graph->RunPass<Licm>(g_options.GetCompilerLicmHoistLimit());
    graph->RunPass<LicmConditions>();
    graph->RunPass<RedundantLoopElimination>();
    graph->RunPass<LoopPeeling>();
    graph->RunPass<PhiTypeResolving>();
    graph->RunPass<Lse>();
    graph->RunPass<ValNum>();
    if (graph->RunPass<Peepholes>() && graph->RunPass<BranchElimination>()) {
        graph->RunPass<Peepholes>();
        graph->RunPass<ValNum>();
    }
    graph->RunPass<Cleanup>();
    if (graph->IsAotMode()) {
        graph->RunPass<Cse>();
    }
    graph->RunPass<ChecksElimination>();
    graph->RunPass<LoopUnroll>(g_options.GetCompilerLoopUnrollInstLimit(), g_options.GetCompilerLoopUnrollFactor());
    graph->RunPass<BalanceExpressions>();
    if (graph->RunPass<Peepholes>()) {
        graph->RunPass<BranchElimination>();
    }
    graph->RunPass<ValNum>();
    if (graph->IsAotMode()) {
        graph->RunPass<Cse>();
    }
    bool deoptElim = graph->RunPass<DeoptimizeElimination>();
    bool saveStateOpt = graph->RunPass<SaveStateOptimization>();
    if (deoptElim || saveStateOpt) {
        graph->RunPass<Peepholes>();
    }

#ifndef NDEBUG
    graph->SetLowLevelInstructionsEnabled();
#endif  // NDEBUG
    graph->RunPass<Cleanup>(false);
    graph->RunPass<Lowering>();
    graph->RunPass<Cleanup>(false);
    graph->RunPass<CodeSink>();
    graph->RunPass<MemoryCoalescing>(g_options.IsCompilerMemoryCoalescingAligned());
    graph->RunPass<IfConversion>(g_options.GetCompilerIfConversionLimit());
    graph->RunPass<Scheduler>();
    // Perform MoveConstants after Scheduler because Scheduler can rearrange constants
    // and cause spillfill in reg alloc
    graph->RunPass<MoveConstants>();
    graph->RunPass<AdjustRefs>();
    graph->RunPass<OptimizeMemoryBarriers>();

    return true;
}

}  // namespace ark::compiler::ecmascript
